#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include "ZipManager.h"
#include "FileUtils.h"
#include "ConsoleManager.h"
#include "InputUtils.h"

const Reply ConsoleManager::printHelpMessage()
{
    std::string helpMessage = HELP_MS;
    helpMessage += COMPRESS_MS;
    helpMessage += DECOMPRESS_MS;
    helpMessage += LIST_MS;
    Reply reply(helpMessage.c_str(), 1);
    printf("%s", helpMessage.c_str());

    return reply;
}

const Reply ConsoleManager::navigate(const char* path)
{
    ZipManager* manager = new ZipManager();
    char* name = getSimpleName(path);

    printf("Navigate: %s\n\n", name);
    manager->openFile(path);

    ZipNavigator::maxFileNameLength_ = 0;
    manager->traverse(ZipNavigator::calculateMaxFileNameLength);
    std::cout.width(ZipNavigator::maxFileNameLength_ + 1);
    std::cout << std::left << "File Name";
    std::cout.width(26);
    std::cout << std::left << "Last modification time";
    std::cout.width(5);
    std::cout << std::right << "comp %\n\n";

    manager->navigate();

    const Reply res("Navigate");

    delete manager;
    return res;
}

const Reply ConsoleManager::compress(const char* fileName, const char* output, std::vector<std::string> pathList)
{
    ZipManager* manager = new ZipManager();
    manager->compress(modifyFileName(fileName), output, pathList);
    delete manager;
    const Reply compress("Compress");
    printf("Successfully compressed!\n");
    return compress;
}

const Reply ConsoleManager::decompress(const char* output, const char* input)
{
    if(isDirectory(output))
    {
        ZipManager* manager = new ZipManager();
        manager->openFile(input);
        manager->decompress(output);
        printf("Successfully decompressed!\n");
        delete manager;
    }
    else
    {
        throw ZipException("\nInvalid directory argument the directory doesn't exists\n");
    }
    const Reply compress("Decompress");

    return compress;
}

void ConsoleManager::checkArgument(int argc, char command)
{
    std::string message = NOT_ARG_MS;

    switch(command)
    {
        case 'l':
            if(argc != 3)
            {
                message += LIST_MS;
                throw ZipException(message.c_str());
            }
            break;
        case 'c':
            if(argc < 5)
            {
                message += COMPRESS_MS;
                throw ZipException(message.c_str());
            }
            break;
        case 'd':
            if(argc != 4)
            {
                message += DECOMPRESS_MS;
                throw ZipException(message.c_str());
            }
    }
}

std::vector<std::string> ConsoleManager::getPathList(int begin, int end, char** argv)
{
    std::vector<std::string> pathList;

    for(int i = begin; i < end; i++)
    {
        char* path = argv[i];
        
        if(isFile(path) || isDirectory(path))
        {
            pathList.push_back(path);
        }
    }
    return pathList;
}

const Reply ConsoleManager::executeCommand(int argc, char** argv)
{
    Reply res;

    if(argc > 1)
    {
        try
        {
            char comand = argv[1][1];
            switch(comand)
            {
                case 'l':
                    checkArgument(argc, comand);
                    return navigate(argv[2]);
                    break;
                case 'c':
                    checkArgument(argc, comand);
                    return compress(argv[2], argv[3], getPathList(4, argc, argv));
                    break;
                case 'd':
                    checkArgument(argc, comand);
                    return decompress(argv[2], argv[3]);
                    break;
                default:
                    return printHelpMessage();

            }
        }catch(exception& e)
        {
            printf("%s\n", e.what());
            res.message_ = e.what();
            res.code_ = 1;
        }

    }
    else
    {
        res = printHelpMessage();
    }

    return res;
}
